home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 37 / Amiga Format CD37 (1999-02-16)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-03].iso / -screenplay- / shareware / invasionforce / source / cyber4.c < prev    next >
C/C++ Source or Header  |  1999-01-09  |  34KB  |  997 lines

  1. /*
  2. AI Code for Invasion Force - an Explore/Conquer Strategic Wargame
  3. Copyright (C) 1996  Brannen Hough
  4.  
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. /*
  20.     cyber4.c -- artificial intelligence module for Empire II
  21.  
  22. */
  23.  
  24. /* This file contains all the routines associated with AI Type #4.
  25. */
  26.  
  27. #include "global.h"
  28. #define SHOW_AI4_MSG
  29. #ifdef SHOW_AI4_MSG
  30. #define  DEBUG_AI4(string)  if (!rtEZRequestTags(string,"Continue|Abort", \
  31.      NULL,NULL, RTEZ_Flags,EZREQF_CENTERTEXT,RT_Window,map_window, \
  32.      RT_ReqPos,REQPOS_CENTERWIN,RT_LockWindow,TRUE,TAG_END )) \
  33.      { if (AIhandle != NULL)  unpost_it(AIhandle); AIhandle = NULL; \
  34.      clean_exit(0, NULL); }
  35. #endif
  36. #ifndef SHOW_AI4_MSG
  37. #define  DEBUG_AI4(string)
  38. #endif
  39.  
  40.  
  41.  
  42. #define GET_REQ 10
  43. void  AI4_set_gov_prod (struct City *metro, struct GovNode *CityOwner)
  44. {       
  45.     struct GovNode *Gov = (struct GovNode *)GovList.mlh_Head;
  46.     struct GovReqs  allreqs[ GET_REQ ];
  47.     int i, lowest_pri, lowest_ind, total_pri = 0;
  48.     int rand_pri;
  49.  
  50.     /* Go through the list of Governors.  We find the 10 governors with
  51.        the highest priority requests, and pick one at random based on the
  52.        relative priorities (i.e. a request of priority 5 is 5 times
  53.        more likely to be honored than a request of priority 1) and make
  54.        that requested unit. */
  55.  
  56.     /* Lets do some error checking */
  57.     CityOwner->req.req_gov = -1;
  58.     CityOwner->req.priority = 0;
  59.     CityOwner->req.type = -1;
  60.  
  61.     /* Let's initialize the 10 requests */
  62.     for (i=0; i < GET_REQ; i++) {
  63.         allreqs[i].req_gov = -1;
  64.         allreqs[i].priority = 0;
  65.         allreqs[i].type = -1;
  66.     }
  67.         
  68.     for ( ; Gov->gnode.mln_Succ; Gov = (struct GovNode *)Gov->gnode.mln_Succ) {
  69.         if (Gov->owner == player) {
  70.         LastReq.req_gov = -1;
  71.         LastReq.priority = 0;
  72.         LastReq.type = -1;
  73.             AI4_get_gov_req (Gov, metro );
  74.         if( LastReq.priority > 0 ) {
  75.         /* Add it to the list if it is one of the top whatever */
  76.         lowest_pri = 1000;
  77.         lowest_ind = -1;
  78.         for( i=0; i < GET_REQ; i++ ) {
  79.             if( allreqs[i].priority < lowest_pri ) {
  80.             lowest_ind = i;
  81.             lowest_pri = allreqs[i].priority;
  82.             }
  83.         }
  84.         if( lowest_ind != -1 ) {
  85.             allreqs[lowest_ind].req_gov = LastReq.req_gov;
  86.             allreqs[lowest_ind].priority = LastReq.priority;
  87.             allreqs[lowest_ind].type = LastReq.type;
  88.         }
  89.         }
  90.     }
  91.     } /* End for */
  92.     /* Now go through the list and total up the priorities, then pick a 
  93.        random number from 1 to the total */
  94.     for( i=0; i < GET_REQ; i++) {
  95.     total_pri += allreqs[i].priority;
  96.     }
  97.     rand_pri = RangeRand( (long) (total_pri -1) ) + 1;
  98.  
  99.     /* Now select the random one we picked */
  100.     lowest_ind = -1;
  101.     while( rand_pri > 0 ) {
  102.     rand_pri -= allreqs[++lowest_ind].priority;
  103.     }
  104.     if( (lowest_ind < 0) || (lowest_ind > (GET_REQ -1)) ) {
  105.     /* Error - out of bounds */
  106.     DEBUG_AI("Out of bounds for production selection randomizer")
  107.         /* Well, make another of whatever we were making. */
  108.     CityOwner->req.req_gov = CityOwner->ID;
  109.     if( ( metro->unit_type >=0 ) && (metro->unit_type <= CARRIER) ) {
  110.         CityOwner->req.type = metro->unit_type;
  111.     }
  112.     else {
  113.         /* Need to make sure we have a decent fall-back: make an 
  114.            Infantry for the owning governor - we can always use 
  115.            Infantry */
  116.         metro->unit_type = RIFLE;
  117.         CityOwner->req.type = RIFLE;
  118.     }
  119.         return;
  120.     }
  121.     else {
  122.     /* Make the selected type of unit */
  123.     CityOwner->req.priority = LastReq.priority;
  124.     CityOwner->req.type = LastReq.type;
  125.     CityOwner->req.req_gov = LastReq.req_gov;
  126.     sprintf(outbuf, "Producing a %s for Governor %ld",
  127.         UnitString[CityOwner->req.type], CityOwner->req.req_gov);
  128.     DEBUG_AI(outbuf)
  129.     
  130.     /* And we set the city itself to produce this */
  131.     if (metro->unit_type != CityOwner->req.type) {  /*making a new type*/
  132.         metro->unit_type = CityOwner->req.type;
  133.         /*Tooling up penalty */
  134.         metro->unit_wip = -1 * wishbook[metro->unit_type].build/5;
  135.         sprintf (outbuf, "Tooling Up the city to build a %s",
  136.              UnitString[metro->unit_type]);
  137.         DEBUG_AI(outbuf)
  138.     }
  139.     /* unit->wip has been set to zero elsewhere.  Don't zero out 
  140.        production that has already been started when we haven't 
  141.        changed the type. We have enough handicaps as it is.
  142.        */
  143.     }
  144.     return;
  145. }
  146.  
  147.  
  148. void  AI4_get_gov_req( struct GovNode* Gov, struct City* metro )
  149. {
  150.     int  HaveInfAccess = 0;
  151.     int  HaveArmAccess = 0;
  152.     int  i;
  153.     
  154.     /* We assume we get the global LastReq structure with all invalid
  155.        fields, so no request is made if we don't fill them in.
  156.        */
  157.     if( IsCityTaken(Gov) ) {
  158.         /* We need ground troops if they can reach us, else Air Cav if 
  159.             they are available and can reach us, else skip this city -
  160.             it's too far away and we don't do ships yet. */
  161.         if( wishbook[AIRCAV].enabled == TRUE) {
  162.             AI5_CalcPath( RIFLE, metro->col, metro->row,
  163.                      Gov->x, Gov->y, AI5_PATH_GOOD );
  164.             HaveInfAccess = Path[0];
  165.             if( HaveInfAccess != -1 ) {
  166.                 AI5_CalcPath( ARMOR, metro->col, metro->row,
  167.                      Gov->x, Gov->y, AI5_PATH_GOOD );
  168.                 HaveArmAccess = Path[0];
  169.             }
  170.             else {
  171.                 HaveArmAccess = -1;
  172.             }
  173.             if( HaveInfAccess != -1 ) {  /* Access by ground forces */
  174.                 LastReq.priority = 30;
  175.                 /* No type selected yet, lets get a ground unit */
  176.                 /* Make armor units if we can, if not, make infantry. */
  177.                 LastReq.type = ARMOR;
  178.         
  179.                 /* Now, change back if we can't make an armor or they can't
  180.                    reach the destination. */
  181.                 if( (wishbook[ARMOR].enabled != TRUE) || 
  182.                     (HaveArmAccess == -1)) {
  183.                     LastReq.type = RIFLE;
  184.                 }
  185.                 /* And, change it back if the area of interest is 
  186.                    not good for armor
  187.                    */
  188.                 if((Gov->hist.TerrainCounts[HEX_PLAINS] +
  189.                     Gov->hist.TerrainCounts[HEX_DESERT] + 
  190.                     //Gov->hist.TerrainCounts[HEX_ARCTIC] + 
  191.                     Gov->hist.TerrainCounts[HEX_BRUSH]) 
  192.                            < 
  193.                    ((Gov->hist.TerrainCounts[HEX_JUNGLE] + 
  194.                     Gov->hist.TerrainCounts[HEX_PEAKS] + 
  195.                     Gov->hist.TerrainCounts[HEX_SWAMP] + 
  196.                     Gov->hist.TerrainCounts[HEX_MOUNTAINS]) * 2) )
  197.                     LastReq.type = RIFLE;
  198.             }
  199.             else { /* No access by ground forces */
  200.                 if( (AI5_GetDist( metro->col, metro->row, Gov->x,
  201.                   Gov->y ) <= 12) && (wishbook[AIRCAV].enabled == TRUE) ) { 
  202.                     /* distance is <= 12 AND we can make AirCav */
  203.                     LastReq.type = AIRCAV;
  204.                     LastReq.priority = 30;
  205.                 }
  206.                 /* Else, no request at all */
  207.             }
  208.         } /* End if we can make AIRCAV */
  209.         else {
  210.                 LastReq.type = ARMOR;
  211.                 /* Now, change back if we can't make an armor or they can't
  212.                    reach the destination. */
  213.                 if( wishbook[ARMOR].enabled != TRUE)
  214.                     LastReq.type = RIFLE;
  215.                     
  216.                 /* And, change it back if the area of interest is 
  217.                    not good for armor
  218.                    */
  219.                 if((Gov->hist.TerrainCounts[HEX_PLAINS] +
  220.                     Gov->hist.TerrainCounts[HEX_DESERT] + 
  221.                     //Gov->hist.TerrainCounts[HEX_ARCTIC] + 
  222.                     Gov->hist.TerrainCounts[HEX_BRUSH]) 
  223.                            < 
  224.                    ((Gov->hist.TerrainCounts[HEX_JUNGLE] + 
  225.                     Gov->hist.TerrainCounts[HEX_PEAKS] + 
  226.                     Gov->hist.TerrainCounts[HEX_SWAMP] + 
  227.                     Gov->hist.TerrainCounts[HEX_MOUNTAINS]) * 2) )
  228.                     LastReq.type = RIFLE;
  229.         } /* End else can't make AIRCAV */                    
  230.     }
  231.     else {
  232.         switch( Gov->mode ) {
  233.         case GOV_DEFEND:
  234.             /* We're under attack!  Make some ground units to defend 
  235.                with */
  236.             LastReq.priority = 20;
  237.             /* But, let's only change production if it's not ARMOR */
  238.             if( metro->unit_type == ARMOR ) 
  239.                 LastReq.type = ARMOR;
  240.             else
  241.                 LastReq.type = RIFLE;
  242.             break;
  243.         case GOV_SEARCH:
  244.             /* Make aircraft to scout with if we can. */
  245.             LastReq.priority = 10;
  246.             if( wishbook[FIGHTER].enabled == TRUE )
  247.                 LastReq.type = FIGHTER;
  248.             else { 
  249.                 if( wishbook[BOMBER].enabled == TRUE ) {
  250.                     LastReq.type = BOMBER;
  251.                 }
  252.                 else {
  253.                     if( LastReq.type == -1 ) {
  254.                         /* No type selected yet, lets get a ground unit */
  255.                         /* Make armor units if we can, if not, 
  256.                             make infantry. */
  257.                         LastReq.type = ARMOR;
  258.             
  259.                         /* Now, change back if we can't make an armor */
  260.                         if (wishbook[ARMOR].enabled != TRUE) {
  261.                             LastReq.type = RIFLE;
  262.                         }   
  263.                         /* And, change it back if the area of interest is 
  264.                            not good for armor
  265.                            */
  266.                         if((Gov->hist.TerrainCounts[HEX_PLAINS] +
  267.                             Gov->hist.TerrainCounts[HEX_DESERT] + 
  268.                             //Gov->hist.TerrainCounts[HEX_ARCTIC] + 
  269.                             Gov->hist.TerrainCounts[HEX_BRUSH]) 
  270.                                    < 
  271.                            ((Gov->hist.TerrainCounts[HEX_JUNGLE] + 
  272.                             Gov->hist.TerrainCounts[HEX_PEAKS] + 
  273.                             Gov->hist.TerrainCounts[HEX_SWAMP] + 
  274.                             Gov->hist.TerrainCounts[HEX_MOUNTAINS]) * 2) )
  275.                                 LastReq.type = RIFLE;
  276.                     } /* End else no unit type selected yet */
  277.                 } /* End else no bombers */
  278.             } /* End else no fighters */
  279.             /* If we have a bunch of Fighters already, start making
  280.                some Bombers.  But switch back when the Fighters are
  281.                all gone (and try to regain air superiority)
  282.                */
  283.             if((LastReq.type == FIGHTER) &&
  284.                ( wishbook[BOMBER].enabled == TRUE) && 
  285.                (Gov->hist.UnitCounts[FIGHTER] >= 5) ) {
  286.                     LastReq.type = BOMBER;
  287.             }
  288.             break;
  289.         } /* End switch */
  290.     } /* End else not city-taken */
  291.  
  292.     /* Attenuate the priority of the request for distance */
  293.     if( LastReq.priority > 0 ) {
  294.         i = AI5_GetDist (metro->col, metro->row, Gov->x, Gov->y);
  295.         LastReq.priority -= i / 2;
  296.         if (LastReq.priority < 1)  LastReq.priority = 1;
  297.     }
  298.     /* And make sure we record who made the request */
  299.     if( LastReq.type != -1 )
  300.         LastReq.req_gov = Gov->ID;
  301.     else 
  302.         LastReq.priority = 0;
  303.  
  304.     return;
  305. }
  306.  
  307.  
  308. struct GovNode*  AI4_locate_gov( struct City* metro )
  309. {
  310.     struct GovNode *Gov = (struct GovNode *)GovList.mlh_Head;
  311.     struct GovNode *NewGov = NULL;
  312.  
  313.     for ( ; Gov->gnode.mln_Succ; Gov = (struct GovNode *)Gov->gnode.mln_Succ) {
  314.     if ((Gov->owner == player) && 
  315.         ((Gov->type == GOV_CITY) || (Gov->type == GOV_PORT) || 
  316.         (Gov->type == GOV_ISLAND))
  317.         && (Gov->x == metro->col) && (Gov->y == metro->row)) {
  318.         /* We found the right city governor. */
  319.         return( Gov );
  320.     }  /* End if */
  321.     } /* End for loop */
  322.  
  323.     DEBUG_AI("Couldn't find the governor, making one")
  324.     /* Never found it */
  325.     NewGov = AI3_add_gov( metro );
  326.     /* And, let's set up the governors area of interest */
  327.     AI3_setup_area_of_interest (NewGov, 5, 20);
  328.     return (NewGov);
  329. }
  330.  
  331. void  AI4_play_turn( int new_units )
  332. {
  333.     int   MaxLooping = 5000;
  334.     /* Here we may want to look around, give out some orders to units,
  335.        and execute orders to units in a loop until we have done all the 
  336.        moves possible for the units.
  337.        */
  338.     AI3_do_all_histograms();
  339.     AI4_give_orders();
  340.     /* We'll add a little failsafe so we don't spend eternity here */
  341.     while( (MaxLooping > 0) && (!DoUnitActions(40,60)) )  MaxLooping--;
  342.     if( MaxLooping <= 0 ) 
  343.         DEBUG_AI4("Error: Exitting AI player's turn - out of actions!")
  344.     return;
  345. }
  346.  
  347. int  AI4_do_unit_actions()
  348. {
  349.     struct Unit *unit = (struct Unit *)unit_list.mlh_Head;
  350.     struct GovNode *Gov = NULL;
  351.     int         Done = TRUE;
  352.     static struct Unit* lastunit = NULL;
  353.     static int    times_accessed = 0;
  354.     int           attack_dir;
  355.  
  356.     for ( ; unit->unode.mln_Succ; unit = (struct Unit *) unit->unode.mln_Succ)
  357.         if ((unit->owner==player) && (unit->move > 0)) {
  358.         /* Added this last to only give any one unit 10 chances to
  359.            move - if it hasn't by then, skip over it and go to the
  360.            next.  This has the pleasant effect that the unit that
  361.            couldn't move in 10 tries will get another 10 tries to
  362.            move, and so on, until it finally gets skipped for this
  363.            turn. */
  364.         if ( (lastunit != unit) || (times_accessed < 10) )  {
  365.             if( lastunit != unit ) {
  366.                 lastunit = unit;
  367.                 times_accessed = 0;
  368.             }
  369.             else {
  370.                 times_accessed++;
  371.             }
  372.             /* Skip Sentry units */
  373.             if ((unit->orders != NULL) && 
  374.                 (unit->orders->reserved == C_ORDER_SENTRY))   
  375.                 continue;
  376.             /* Take a look around us and react to enemy units + cities */
  377.             /* New for this version - let's use the recommend action
  378.                routine. */
  379.             //attack_dir = AI4_recommend_action( unit, 75, 20);
  380.             //if( attack_dir != -1 ) {
  381.                 //move_unit_dir( unit, attack_dir );
  382.                 //return (FALSE);
  383.             //}
  384.             if( AI4_look_around ( unit ) )   return (FALSE);
  385.             /* if we have orders, execute them */
  386.             if (unit->orders != NULL) {
  387.                 AI4_execute_standing_order(unit);
  388.                 return (FALSE);
  389.             }
  390.         
  391.             else {
  392.                 /* We don't have orders, so try to wing it! */
  393.                 Gov = AI1_FindOwner (unit);
  394.                 if (Gov != NULL) {
  395.                     DEBUG_AI("No orders, no enemy around. Huh?")
  396.                     /* Just skip this unit this turn - the 
  397.                         governor willgive new orders next turn. */
  398.                     unit->move = 0;
  399.                 } /* End if Gov != NULL */
  400.                 else {
  401.                     DEBUG_AI("Cannot find unit owner to ad lib turn")
  402.                     DEBUG_AI("For Now, Forget IT!")
  403.                     sprintf (outbuf, "%s Unit %s at %ld,%ld",
  404.                          UnitString[unit->type], unit->name, 
  405.                          unit->col, unit->row);
  406.                     DEBUG_AI(outbuf)
  407.                     unit->move = 0;
  408.                 } /* End else Gov == NULL */
  409.             } /* End else figure something out */
  410.         } /* End if the unit is not the same one we accessed 10 times */
  411.         else {
  412.             /* Last unit IS this unit and times accessed >= 10. */
  413.             /* This should ensure that we never get stuck forever - we
  414.                will always finish - removes a potential infinite loop
  415.                when there are TWO enemy planes, over water, that can be
  416.                attacked by ground troops.  They will ping pong between
  417.                them forever. */
  418.             unit->move-=10;
  419.             times_accessed = 0;
  420.             lastunit = NULL;
  421.         }
  422.     } /* End if we own unit and it has moves left */
  423.     /* End for loop */    
  424.     times_accessed = 0;
  425.     lastunit = NULL;
  426.     return (Done);
  427. }
  428.  
  429. int  AI4_look_around( struct Unit* unit)
  430. {
  431.     int          i, k;
  432.     short        targx, targy;
  433.     struct City* metro;
  434.     struct GovNode* FoundGov = NULL;
  435.     struct GovNode* my_gov = NULL;
  436.     enum   GovMode  old_mode;
  437.  
  438.     for (i = 0; i < 6; i++) {
  439.     if (AI1_calc_dir (i, unit->col, unit->row, &targx, &targy) != -1) {
  440.         if ((metro = city_hereP (targx, targy)) && 
  441.         (metro->owner != player)) {
  442.         /* if there is a city here and we don't own it, this
  443.            call will create a Governor for it if there isn't
  444.            one already. 
  445.            */
  446.         FoundGov = AI4_locate_gov( metro ); 
  447.         /* And let the new Gov take a look around */
  448.         AI1_do_one_histogram (FoundGov);
  449.         AI3_set_gov_mode (FoundGov);
  450.         /* Then, try to take it */
  451.           if ((unit->type == RIFLE) || (unit->type == ARMOR)
  452.             || (unit->type == AIRCAV)) {
  453.             /* Go for it! */
  454.             /* DEBUG_AI("Jumping enemy city") */
  455.             /* We can check here that we can GET to the city
  456.                and at least tried to take it, bogged down, etc.
  457.                */
  458.             if( move_unit_xy (unit, targx, targy) <= -2) {
  459.                 return (1);
  460.             }
  461.             /* Else, look around for something else to attack -
  462.              another city, an enemy unit, etc.
  463.              */
  464.           } /* End if can take city */
  465.         if( (unit->type == BOMBER) && (metro->owner != 0)) {
  466.             if( (!unit->orders) || 
  467.             (unit->orders->reserved != C_ORDER_RECON)) {
  468.             /* if we can't take it - bomb it! But it is no use
  469.                bombing a neutral city. Also, if we are on recon,
  470.                don't bomb either.
  471.                */
  472.             move_unit_xy (unit, targx, targy);
  473.             return (1);
  474.             }
  475.         }
  476.         } /* End if city here and it ain't ours! */
  477.     } /* End if hex here */
  478.     } /* End For loop */
  479.     for (i = 0; i < 6; i++) {
  480.     if (AI1_calc_dir (i, unit->col, unit->row, &targx, &targy) != -1) {
  481.         if (((k = hex_owner(targx,targy)) > 0)&&(k!=player)) {
  482.         if((!unit->orders) || 
  483.            (unit->orders->reserved != C_ORDER_RECON) ) {
  484.             /*DEBUG_AI("Jumping enemy unit") */
  485.             /* Add the if statement so that we keep trying to attack
  486.                 an enemy until we succeed or have tried each direction
  487.                 once.  There are cases (like an aircraft over water
  488.                 attacked by a ground unit) where attacks can't take
  489.                 place. */
  490.             /* Here's a new experiment - changing our governor's
  491.                mode on the fly.
  492.                */
  493.             my_gov = AI1_FindOwner( unit );
  494.             if( my_gov) {  /* Just to be safe */
  495.             AI1_do_one_histogram( my_gov );
  496.             old_mode = my_gov->mode;
  497.             AI3_set_gov_mode( my_gov );
  498.             if( old_mode != my_gov->mode ) {
  499.                 /* We need to issue new orders to our units */
  500.                 AI4_give_orders();
  501.             }
  502.             }
  503.             if( move_unit_xy (unit, targx, targy) <= -2 ) {
  504.                 /* We successfully attacked, ran out of gas, couldn't
  505.                     move, etc. */
  506.                 return (1);
  507.             }
  508.             if( !AI3_AssertUnit(unit) ) return (1);
  509.         }
  510.         /* Else, try a different enemy unit */
  511.         }  /* End if bad guy here */
  512.     } /* End if hex here */
  513.     } /* End for loop */
  514.     return (0);
  515. }
  516.  
  517.  
  518. void  AI4_execute_standing_order( struct Unit* unit )
  519. {
  520.     int        result;
  521.  
  522.     if ((unit->orders == NULL) || (unit->orders->type != ORDER_NONE)) {
  523.     DEBUG_AI("Big problem in execute_standing_order - no orders!")
  524.     sprintf (outbuf, "%s %s has no standing orders to execute - aborting",
  525.          UnitString[unit->type], unit->name);
  526.     DEBUG_AI(outbuf)
  527.     return;
  528.     }
  529.     
  530.     switch (unit->orders->reserved) {
  531.         case  C_ORDER_HEADTO:
  532.             result = AI1_command_headto(unit);
  533.             if( (result <= 0) && (AI3_AssertUnit(unit)) )
  534.                 clear_orders(unit);   /* problem or done */
  535.             break;
  536.         case C_ORDER_GOTO:
  537.             result = AI4_command_goto(unit);
  538.             if( (result <= 0) && (AI3_AssertUnit(unit)) )
  539.                    clear_orders(unit);   /* problem or done */
  540.             break;
  541.         case  C_ORDER_RANDOM:
  542.             AI3_command_random(unit);
  543.             break;
  544.         case  C_ORDER_HUNT:
  545.             result = AI2_command_hunt(unit);
  546.             if( (result < 0) && (AI3_AssertUnit(unit)) )
  547.                 clear_orders(unit);  /* wouldn't work */
  548.             break;
  549.         case  C_ORDER_RECON:
  550.             result = AI3_command_recon(unit);
  551.             if( (result <= 0) && (AI3_AssertUnit(unit)) )
  552.                  clear_orders(unit);  /* problem */
  553.             break;
  554.         case  C_ORDER_WALK_COASTLINE:
  555.             result = AI4_command_walk_coastline( unit );
  556.             if( (result <= 0) && (AI3_AssertUnit( unit ) ) )
  557.                 clear_orders( unit );  /* problem or done */
  558.             break;
  559.         default:
  560.             DEBUG_AI("Unknown command type found in execute_standing_order!")
  561.             break;
  562.     }
  563.     return;
  564. }
  565.  
  566.  
  567. void  AI4_give_orders( )
  568. {
  569.     struct  Unit   *unit = (struct Unit *)unit_list.mlh_Head;
  570.    
  571.     for (;unit->unode.mln_Succ; unit = (struct Unit *)unit->unode.mln_Succ) 
  572.         if ((unit->owner == player) && (unit->move > 0) && 
  573.             (unit->orders == NULL)) {
  574.             /* No orders yet, let's set some
  575.            Ok, we own the unit, and it has moves left, and has a Governor
  576.            owner, and has no standing orders
  577.            Don't just stand there, do something!
  578.            */
  579.             //sprintf(outbuf, 
  580.             //"Giving initial orders to unit named %s at %ld,%ld", 
  581.             //   unit->name, unit->col, unit->row);
  582.             //   DEBUG_AI(outbuf)
  583.         AI4_orders_for_unit( unit );
  584.     } /* end if owner and has moves left */
  585.     /* End For */
  586. }
  587.  
  588. void  AI4_orders_for_unit( struct Unit* unit )
  589. {
  590.     struct GovNode *Gov = AI1_FindOwner (unit);
  591.     if (Gov != NULL) {
  592.         if( IsCityTaken( Gov ) ) {
  593.         AI4_taken_orders( unit, Gov );
  594.     } /* End if CityTaken */
  595.     else {
  596.         switch( Gov->mode ) {
  597.             case GOV_DEFEND:  {
  598.             AI4_defend_orders( unit, Gov );
  599.             break;
  600.         } /* End if mode = defend */
  601.             case GOV_SEARCH: {
  602.             AI3_search_orders( unit, Gov );
  603.             break;
  604.         }
  605.             default: {
  606.             AI3_default_orders( unit, Gov );
  607.             break;
  608.         }
  609.         } /* End switch */
  610.     } /* End else city is not taken */
  611.     } /* End if Gov is not equal to NULL */
  612.     else {
  613.         /* Can't find owner */
  614.         AI3_default_orders( unit, Gov );
  615.     }
  616. }
  617.  
  618. void  AI4_taken_orders( struct Unit* unit, struct GovNode* Gov )
  619. {
  620.     char outbuf[20];
  621.     struct GovNode* Gov2 = NULL;
  622.     struct MapIcon* icon = NULL;
  623.     /* For taken cities, we want the air units to retreat to another
  624.        city (if possible) or else attack any enemy in sight.  Aircav
  625.        should try to retake the city if they can.  Armor and Infantry
  626.        should also retake the city like AI #2.
  627.        */
  628.     switch( unit->type ) {
  629.     case FIGHTER:
  630.     /* Deliberate fall through */
  631.     case BOMBER:
  632.     Gov2 = AI3_FindClosestCityGov( unit, unit->fuel );
  633.     if( Gov2 ) {
  634.         ComputerGiveOrders 
  635.         (unit, C_ORDER_GOTO, Gov2->x, Gov2->y, -1, -1, -1);
  636.         /* And defect to that Governor */
  637.         sprintf (outbuf, "%ld / %ld", Gov->ID, NewUnit++);
  638.         name_unit( unit, outbuf);            
  639.     }
  640.     else {
  641.         /* No one else in range - try to take someone with us */
  642.         ComputerGiveOrders 
  643.         (unit, C_ORDER_HUNT, -1, -1, -1, -1, 6);
  644.     }
  645.     break;
  646.     case AIRCAV:
  647.     if( AI5_GetDist( unit->col, unit->row, Gov->x, Gov->y ) 
  648.         <= unit->fuel ) {
  649.         /* We are in range of our own Governor, so go retake it.
  650.            Do or die! */
  651.         ComputerGiveOrders 
  652.         (unit, C_ORDER_GOTO, Gov->x, Gov->y, -1, -1, -1);
  653.     }
  654.     else {
  655.         /* Too far to reach it */
  656.         /* Find nearest city to hole up in */
  657.         Gov2 = AI3_FindClosestCityGov( unit, unit->fuel );
  658.         if( Gov2 ) {
  659.         ComputerGiveOrders 
  660.             (unit, C_ORDER_GOTO, Gov2->x, Gov2->y, -1, -1, -1);
  661.         /* And defect to that Governor */
  662.         sprintf (outbuf, "%ld / %ld", Gov->ID, NewUnit++);
  663.         name_unit( unit, outbuf);            
  664.         }
  665.         else {
  666.         /* What now ? I must be out here for some reason... */
  667.         icon = AI3_FindClosestEnemyCity( unit, unit->fuel );
  668.         if( icon ) {
  669.             /* Go get it! */
  670.             ComputerGiveOrders 
  671.             (unit, C_ORDER_GOTO, icon->col, icon->row, -1, -1,
  672.              -1);
  673.         }
  674.         }
  675.     }
  676.     case RIFLE:
  677.     /* Deliberate fall through */
  678.     case ARMOR:
  679.     /* Come and retake the city */
  680.     ComputerGiveOrders 
  681.         (unit, C_ORDER_GOTO, Gov->x, Gov->y, -1, -1, -1);
  682.     break;
  683.     default:
  684.     DEBUG_AI("Unknown unit type - ignoring")
  685.     break;
  686.     }
  687. }
  688.  
  689.  
  690. void  AI4_defend_orders( struct Unit* unit, struct GovNode* Gov )
  691. {
  692.     struct MapIcon* icon = NULL;
  693.     /* On defense, we have the fighters and bombers seek out enemy units
  694.        and attack them - within their fuel constraints.  Units with less
  695.        than half their fuel will return to their city for fueling before
  696.        assaulting enemy units - unless, of course, they run into them on
  697.        the way.  Aircav will still try to go for the nearest enemy city
  698.        to try and take it (it may be why we are in defend mode).  Ground 
  699.        units will try to attack enemy units or enemy cities (if they are
  700.        closer). This may need some more thought!
  701.           How about this - we make the defining factor whether there are
  702.        enemy units about.  For fighter and bomber aircraft, if there were 
  703.        no enemy units, then go back to recon (they certainly can't help
  704.        take enemy cities).
  705.        */
  706.     switch( unit->type ) {
  707.     case FIGHTER:
  708.     /* Deliberate fall through */
  709.     case BOMBER:
  710.     if( Gov->hist.TotalEUnits > 0 ) {
  711.         if( unit->fuel > (wishbook[unit->type].range / 2) ) {
  712.         /* Go hunting */
  713.         ComputerGiveOrders 
  714.             (unit, C_ORDER_HUNT, -1, -1, -1, -1, 6);
  715.         }
  716.         else {
  717.         /* Return for more fuel */
  718.         ComputerGiveOrders 
  719.             (unit, C_ORDER_GOTO, Gov->x, Gov->y, -1, -1, -1);
  720.         }
  721.     }
  722.     else {
  723.         /* Must be another city we saw - go back to recon */
  724.         if( (unit->col == Gov->x) && (unit->row == Gov->y) ) {
  725.             ComputerGiveOrders 
  726.                 (unit, C_ORDER_RECON, -1, -1, Gov->x, Gov->y, -1 );
  727.             AI3_select_recon_hex( unit, Gov );
  728.         }
  729.         else
  730.         ComputerGiveOrders
  731.             (unit, C_ORDER_GOTO, Gov->x, Gov->y, -1, -1, -1);
  732.     }
  733.     break;
  734.     case AIRCAV:
  735.     icon = AI3_FindClosestEnemyCity( unit, unit->fuel );
  736.     if( icon ) {
  737.         /* Enemy city in range. Go get it! */
  738.         ComputerGiveOrders 
  739.         (unit, C_ORDER_GOTO, icon->col, icon->row, -1, -1, -1);
  740.     }
  741.     else {
  742.         /* None in range - must be enemy units about */
  743.         /* This may not be smart - these are expensive units. */
  744.         if( Gov->hist.TotalEUnits > 0 ) {
  745.         ComputerGiveOrders 
  746.             (unit, C_ORDER_HUNT, -1, -1, -1, -1, 6);
  747.         }
  748.         else {
  749.         /* No one around to attack.  Put in storage */
  750.         if(( unit->col == Gov->x) && ( unit->row == Gov->y) ) {
  751.             ComputerGiveOrders 
  752.             (unit, C_ORDER_SENTRY, -1, -1, -1, -1, -1);
  753.         }
  754.         else {
  755.             /* Return for more fuel */
  756.             ComputerGiveOrders 
  757.             (unit, C_ORDER_GOTO, Gov->x, Gov->y, -1, -1, -1);
  758.         }    
  759.         }
  760.     }
  761.     break;
  762.     case RIFLE:
  763.     /* Deliberate fall through */
  764.     case ARMOR:
  765.     if( Gov->hist.TotalEUnits > 0 ) {
  766.         if( (unit->col > Gov->Estartx) && 
  767.             (unit->col < Gov->Eendx ) &&
  768.             (unit->row > Gov->Estarty) &&
  769.             (unit->row < Gov->Eendy) ) {
  770.             DEBUG_AI("Put 'em on the hunt")
  771.             ComputerGiveOrders 
  772.                 (unit, C_ORDER_HUNT, -1, -1, -1, -1, 6);
  773.         } /* End of if unit in governors extended zone */
  774.         else {
  775.             /* Maybe there is a city nearby to attack? */
  776.             icon = AI3_FindClosestEnemyCity
  777.                 ( unit, 10 );
  778.             if( icon ) {
  779.                 ComputerGiveOrders
  780.                     (unit, C_ORDER_GOTO, icon->col, icon->row, 
  781.                  -1, -1, -1);
  782.             }
  783.             else {
  784.                 ComputerGiveOrders 
  785.                     (unit, C_ORDER_GOTO, Gov->x, Gov->y, 
  786.                  -1, -1, -1);
  787.             }
  788.         } /* End else not in governors extended range */
  789.     }
  790.     else {
  791.         /* No enemy units - must be a city to attack */
  792.         icon = AI3_FindClosestEnemyCity( unit, 100 );
  793.         if( icon ) {
  794.             ComputerGiveOrders
  795.                 (unit, C_ORDER_GOTO, icon->col, icon->row, -1, 
  796.              -1, -1);
  797.         }
  798.         else {
  799.             /* Go back to random wandering - nothing better to do */
  800.               ComputerGiveOrders 
  801.               (unit, C_ORDER_RANDOM, -1, -1, -1, -1, -1);
  802.         }
  803.     }
  804.     break;
  805.     default:
  806.         DEBUG_AI("Unknown unit type - ignoring")
  807.         break;
  808.     } /* End switch */
  809. }
  810.  
  811.  
  812. void AI4_computer_give_orders(struct Unit *unit,int suborder,short destx,
  813.     short desty,short orgx,short orgy,int etc)
  814. {
  815.     struct GovNode* Gov = NULL;
  816.     struct Order *order=AllocVec((long)sizeof(*order),MEMF_CLEAR);
  817.     
  818.    clear_orders(unit);
  819.    if (order) {
  820.       order->destx = destx;
  821.       order->desty = desty;
  822.       unit->orders = order;
  823.       order->type = ORDER_NONE;
  824.       if (orgx == -1)  order->orgx = unit->col;
  825.       else  order->orgx = orgx;
  826.       if (orgy == -1)  order->orgy = unit->row;
  827.       else  order->orgy = orgy;
  828.       order->processed = FALSE;
  829.       order->etc = etc;
  830.       order->reserved = suborder;       /* using reserved for computer
  831.                                   orders so I don't tread on the human
  832.                                   player's tokens. */
  833.                                         
  834.       /* This is set up to be in the order they are used most often,
  835.          and set up so that more order types can be added as needed.
  836.         */
  837.       switch (suborder) {
  838.       case C_ORDER_HEADTO:
  839.         /* Standard stuff only */
  840.          sprintf (outbuf, "%s %s C_ORDER_HEADTO from %ld,%ld to %ld,%ld",
  841.          UnitString[unit->type], unit->name, order->orgx, 
  842.          order->orgy, order->destx, order->desty);
  843.          DEBUG_AI(outbuf)
  844.          
  845.         break;
  846.       case C_ORDER_RECON:
  847.         /* We need to figure out where to recon to - based on the Gov's
  848.            current status of recon elements. */
  849.         Gov = AI1_FindOwner( unit );
  850.         if( Gov ) {
  851.           AI3_select_recon_hex( unit, Gov );
  852.           /* And let's set a failsafe of 1/2 our fuel -1 */
  853.           /* And if this is not an aircraft for some reason 
  854.          (a screwup) this will just get set to -1 anyway */
  855.           order->etc = wishbook[unit->type].range / 2 - 1;
  856.         }
  857.         else {
  858.           /* Can't find the owner - will get sorted out next turn */
  859.         }
  860.         break;
  861.       case C_ORDER_GOTO:
  862.         /* Standard stuff only */
  863.             break;
  864.       case C_ORDER_RANDOM:
  865.         /* Standard stuff only */
  866.         break;
  867.       case C_ORDER_HUNT:
  868.         /* Standard stuff only */
  869.         break;
  870.       case C_ORDER_WALK_COASTLINE:
  871.         /* etc contains clockwise or counter-clockwise */
  872.         order->destx = 0; /* Initial direction */
  873.         order->orgx = unit->col;
  874.         order->orgy = unit->row;
  875.         break;
  876.       case C_ORDER_SENTRY:
  877.         /* Standard stuff only */
  878.         break;
  879.       }
  880.    }
  881. }
  882.  
  883.  
  884. int   AI4_command_walk_coastline( struct Unit* unit )
  885. {
  886.     /* This command will cause the unit (hopefully a ground or naval
  887.        unit) to walk along the coastline, either clockwise (etc = 0)
  888.        or counterclockwise (etc != 0).  Useful for exploring.
  889.        Current direction to start from is kept in destx. The space 
  890.        we started from is kept in orgx, orgy - when we move and end
  891.        up back there we have completed the walk.
  892.        */
  893.     short targx, targy;
  894.     int   current;
  895.     int   new_dir = unit->orders->destx;
  896.     int   result;
  897.  
  898.     if( (unit->orders->destx < 0) || (unit->orders->destx > 5) ) 
  899.         return -1;  /* Problem */
  900.  
  901.     /* Now, figure out where we are headed.  */
  902.     current = AI1_calc_dir( new_dir, unit->col, unit->row, &targx, &targy);
  903.     while(( current != -1) && ( movement_cost_table[unit->type]
  904.        [get(PLAYER.map, targx, targy)] == -1 )) {
  905.         if( unit->orders->etc )
  906.             new_dir++;
  907.         else
  908.             new_dir--;
  909.         /* Wrap around the directions */
  910.         if( new_dir > 5 ) new_dir = 0;
  911.         if( new_dir < 0 ) new_dir = 5;
  912.         /* Check that we haven't come full circle and gotten nowhere */
  913.         if( new_dir == unit->orders->destx )  return -1;
  914.         current = AI1_calc_dir( new_dir, unit->col, unit->row, &targx, &targy);
  915.     } // End while
  916.     /* And, make the move */
  917.     result = move_unit_dir( unit, (enum Direction)new_dir );
  918.  
  919.     /* Examine the result to see if we made a move */
  920.     if( result < -1 )
  921.         /* We lost the unit moving, but made a move (or failed a chance to) */
  922.         return 1;
  923.  
  924.     if( result >= 0 ) {
  925.         if( !AI3_AssertUnit( unit ) ) return -1;  /* Problem! */
  926.         /* We made a move, so check for destination and set up for next move */
  927.         if(unit->orders ) {
  928.             if( (unit->col == unit->orders->orgx) && 
  929.                 (unit->row == unit->orders->orgy) ) {
  930.                 /* We reached the spot we started from - finished (?) */
  931.                 return 0;
  932.             }
  933.             /* Now we have the direction of the first navagable space 
  934.                either CW or CCW from the current spot.  We need to record 
  935.                where to start from next time.
  936.                */
  937.             if( unit->orders->etc )
  938.                 unit->orders->destx = new_dir - 2;
  939.             else
  940.                 unit->orders->destx = new_dir + 2;
  941.             if( unit->orders->destx < 0 ) unit->orders->destx += 6;
  942.             if( unit->orders->destx > 5 ) unit->orders->destx -= 6;
  943.          } //End if unit->orders
  944.     } // End if result >= 0
  945.     /* If the result was -1 (maybe stacking or something?) do nothing */
  946.     return 1;
  947. }
  948.  
  949.  
  950.  
  951. int  AI4_command_goto( struct Unit* unit )
  952. {
  953.     int  i;
  954.     int  result;
  955.  
  956.     /* Check to see if we have arrived */
  957.     if ((unit->col == unit->orders->destx) && 
  958.         (unit->row == unit->orders->desty))  {
  959.         /* We have arrived! */
  960.         /* DEBUG_AI("We have arrived!") */
  961.         return (0);
  962.     }
  963.     /* for now, just ask for the first path we find - after this is sped
  964.        up we can use the optimal path */
  965.     AI5_CalcPath( unit->type, unit->col, unit->row, unit->orders->destx,
  966.                unit->orders->desty, AI5_PATH_GOOD );
  967.     i = Path[0];
  968.     if( (i >=0) && (i <= 5) ) {
  969.         /* We have a valid direction, let's try it. */
  970.         result = move_unit_dir( unit, i );
  971.         if (result == -1)  return -1; // Can't get there from here
  972.         if (result > -3) {
  973.             /* We didn't die in an attack, and we didn't crash, so 
  974.                 let's check for destination again. */
  975.             /*DEBUG_AI("Checking for Destination") */
  976.             if( unit->orders ) {
  977.                 if ((unit->col == unit->orders->destx) && 
  978.                     (unit->row == unit->orders->desty))  {
  979.                     /* We have arrived! */
  980.                     /* DEBUG_AI("We have arrived!") */
  981.                     return (0);
  982.                 }
  983.                 unit->orders->etc--;
  984.                 if (unit->orders->etc < 0)  {
  985.                     DEBUG_AI("Watchdog on HeadTo ran out")
  986.                     return (-2);
  987.                 }
  988.             }
  989.         }
  990.         return (1);
  991.     } // End if valid direction returned
  992.     else {
  993.         return -1;  /* Can't get there */
  994.     }
  995. }
  996.  
  997.